
package edu.hm.devcamp.presentation.activities;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ImageButton;
import android.widget.SlidingDrawer;
import android.widget.SlidingDrawer.OnDrawerCloseListener;
import android.widget.SlidingDrawer.OnDrawerOpenListener;

import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;

import edu.hm.devcamp.R;
import edu.hm.devcamp.communication.GetService;
import edu.hm.devcamp.presentation.LocationListenerImpl;
import edu.hm.devcamp.presentation.NetworkListener;
import edu.hm.devcamp.presentation.overlays.OverlayManager;
import edu.hm.devcamp.providers.ChangeListener;
import edu.hm.devcamp.providers.PoiProviderRequest;
import edu.hm.devcamp.providers.Pois.categories;

public class PoiMap extends MapActivity implements ChangeListener, NetworkListener {

    public static final String FILTER_PREFS_NAME = "myFilterPrefs";

    public static final String PREFS_LIBRARY = "library";

    public static final String PREFS_CULTURE_CENTER = "cultureCenter";

    public static final String PREFS_RECYCLE_SMALL = "recycleSmall";

    public static final String PREFS_RECYCLE_CENTER = "recycleCenter";

    public static final String PREFS_TOILET = "toilet";

    public static final String PREFS_PLAYGROUND = "playground";

    public static final String PREFS_TAXI_STOP = "taxiStop";

    public static final String PREFS_SLIDER_OPEN = "sliderState";

    public static final boolean LOG_D = true;

    public static final boolean LOG_I = true;

    private static final int REFRESH = 1;

    private static final int NO_CONNECTION = 2;

    private static final int SHOW_LOADING = 3;

    private static final int REQUEST_CODE = 1;

    private MapView mMapView;

    private List<Overlay> mMapOverlays;

    private LocationListenerImpl locationListener;

    private LocationManager locationManager;

    private Button mSlideHandleButton;

    private OverlayManager mOverlayManager;

    private SlidingDrawer mSlidingDrawer;

    private ImageButton mCurrentLocation;

    private ImageButton mMapMode;

    private GetService mBoundService;

    private boolean showPlayground = true;

    private boolean showToilet = true;

    private boolean showRecycleSmall = true;

    private boolean showCultureCenters = true;

    private boolean showLibraryOverlay = true;

    private boolean showRecyleCenter = true;

    private boolean showTaxiStop = true;

    private boolean mGetServiceBound = false;

    private ProgressDialog mProgressDialog;

    /**
     * this handler reacts on calls out of other threads (especially the
     * {@link GetService}).
     */
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case REFRESH:
                    // called when the data update was successful
                    if (mProgressDialog != null && mProgressDialog.isShowing()) {
                        mOverlayManager.fillOverlayList(mMapOverlays);
                        refreshView();
                        mProgressDialog.dismiss();
                    }
                    break;
                case NO_CONNECTION:
                    if (mProgressDialog != null && mProgressDialog.isShowing()) {
                        mProgressDialog.dismiss();
                    }
                    // the alert dialog we show when no data connection is
                    // available
                    showOkDialog(R.string.no_connectivity);
                    break;
                case SHOW_LOADING:
                    mProgressDialog = ProgressDialog.show(PoiMap.this, PoiMap.this.getResources()
                            .getString(R.string.progress_header), PoiMap.this.getResources()
                            .getString(R.string.progress_message), true);
                    break;
            }
        }
    };

    /**
     * Service connection for connecting to the get-service.
     */
    private ServiceConnection mGetConnection = new ServiceConnection() {

        public void onServiceConnected(ComponentName className, IBinder binder) {
            GetService.LocalBinder tempBinder = (GetService.LocalBinder)binder;
            mBoundService = tempBinder.getService();
            mBoundService.setListener(PoiMap.this);
            mGetServiceBound = true;

            Intent intent = new Intent(getApplicationContext(), GetService.class);
            intent.putExtra("initial", true);
            PoiMap.this.startService(intent);
        }

        public void onServiceDisconnected(ComponentName className) {
            mBoundService = null;
            mGetServiceBound = false;
        }
    };

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        // Test.test(this);

        // register update listener
        PoiProviderRequest.setListener(this);

        // add map controls
        mMapView = (MapView)findViewById(R.id.mapview);
        mMapView.setBuiltInZoomControls(true);

        mMapOverlays = mMapView.getOverlays();
        mMapOverlays.clear();
        mOverlayManager = OverlayManager.getInstance(this);

        final MapController controller = mMapView.getController();
        controller.setZoom(17);

        // set an on touch listener for the detection of and zoom in at
        // doubletab
        mMapView.setOnClickListener(new OnClickListener() {
            
            long lastClick = 0;

            @Override
            public void onClick(View v) {
                long now = System.currentTimeMillis();
                Log.d("PoiMap", "now-lastclick = " + (now-lastClick));
                if (now - lastClick < 25000000000l) { // doubletab
                    controller.zoomIn();
                } else {
                    lastClick = now;
                }
            }
        });

        mMapMode = (ImageButton)findViewById(R.id.mapmode);
        mMapMode.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                mMapView.setSatellite(!mMapView.isSatellite());
            }
        });

        // register location listener
        locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
        locationListener = new LocationListenerImpl(mMapView, this);
        locationManager
                .requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
        locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0,
                locationListener);

        mCurrentLocation = (ImageButton)findViewById(R.id.current_location);
        mCurrentLocation.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                locationListener.moveToPosition();
            }
        });

        // add slide menu to filter
        mSlideHandleButton = (Button)findViewById(R.id.slideHandleButton);
        mSlidingDrawer = (SlidingDrawer)findViewById(R.id.SlidingDrawer);

        mSlidingDrawer.setOnDrawerOpenListener(new OnDrawerOpenListener() {
            @Override
            public void onDrawerOpened() {
                mSlideHandleButton.setBackgroundResource(R.drawable.handle);
            }
        });
        mSlidingDrawer.setOnDrawerCloseListener(new OnDrawerCloseListener() {
            @Override
            public void onDrawerClosed() {
                mSlideHandleButton.setBackgroundResource(R.drawable.handle_close);
            }
        });

        restoreFilterPrefs();

        // update if the get-service is not yet bound to the activity.
        if (!mGetServiceBound) {
            startService(new Intent(this, GetService.class));
        }

        // check if it's the first start of the app
        checkOnFirstStart();
    }

    @Override
    protected void onPause() {
        super.onPause();
        storeFilterPrefs();
        locationManager.removeUpdates(locationListener);
    }

    @Override
    protected void onResume() {
        // TODO Auto-generated method stub
        super.onResume();
        locationManager
                .requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
        locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0,
                locationListener);
    }

    @Override
    protected void onStart() {
        super.onStart();

        String provider = Settings.Secure.getString(getContentResolver(),
                Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
        provider = provider.trim();

        if (provider == null || provider.equals("")) {
            showOkDialog(R.string.no_gps);
        } else
            Log.d("HelloMapView", "gps string is = " + provider);

        mOverlayManager.fillOverlayList(mMapOverlays);
       
        refreshView();
        

        // if there is only the current position or nothing in the
        // overlays list, we assume it's empty.
        if (mMapOverlays == null || mMapOverlays.size() <= 1) {
            mHandler.sendEmptyMessage(SHOW_LOADING);

            Intent intent = new Intent(getApplicationContext(), GetService.class);
            intent.putExtra("initial", true);
            bindService(intent, mGetConnection, BIND_AUTO_CREATE);
        }
    }

    @Override
    protected void onStop() {
        super.onStop();

        mMapOverlays.clear();
        if(mProgressDialog != null && mProgressDialog.isShowing()){
            mProgressDialog.dismiss();
        }
    }

    @Override
    protected boolean isRouteDisplayed() {
        return false;
    }

    /* is called to create the menue */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.map_menu, menu);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.about:
                startActivity(new Intent(this, AboutView.class));
                return true;
            case R.id.help:
                startActivity(new Intent(this, HelpView.class));
                return true;
            case R.id.ar:
                startActivity(new Intent(this, GeoAR.class));
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_CODE && resultCode == 0) {
            // check whether the user enabled position updates or not
            String provider = Settings.Secure.getString(getContentResolver(),
                    Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
            provider = provider.trim();

            // if not, our application cannot be used.
            if (provider == null || provider.equals("")) {
                showOkDialog(R.string.no_gps);
            }
        }
    }

    public void refreshView() {
        if (PoiMap.LOG_D) {
            Log.w("Sam", "calling refreshView...");
        }

        Set<categories> selectedCats = new HashSet<categories>();
        if (this.showCultureCenters)
            selectedCats.add(categories.culturalCenter);
        if (this.showLibraryOverlay)
            selectedCats.add(categories.library);
        if (this.showPlayground)
            selectedCats.add(categories.playground);
        if (this.showRecycleSmall)
            selectedCats.add(categories.recycleSmall);
        if (this.showRecyleCenter)
            selectedCats.add(categories.recycleCenter);
        if (this.showTaxiStop)
            selectedCats.add(categories.taxiStop);
        if (this.showToilet)
            selectedCats.add(categories.toilet);
        if (PoiMap.LOG_D) {
            Log.d("HelloMapView", "refreshView called");
        }
        mMapOverlays = mOverlayManager.fillOverlaysWithFollowing(mMapOverlays, selectedCats);
        mMapView.invalidate();
    }

    private void showOkDialog(final int stringId) {
        AlertDialog.Builder builder = new AlertDialog.Builder(PoiMap.this);
        builder.setMessage(stringId).setCancelable(true)
                .setNeutralButton("OK", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        switch (stringId) {
                            case R.string.no_connectivity:
                                PoiMap.this.finish();
                                break;
                            case R.string.no_gps:
                                dialog.cancel();
                                Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                                startActivityForResult(intent, REQUEST_CODE);
                        }
                    }
                });
        builder.create().show();
    }

    /**
     * Restores saved Filter Preferences
     */
    private void restoreFilterPrefs() {

        // Toast.makeText(this, "RESTORING DATA", Toast.LENGTH_SHORT);
        // Restore preferences
        SharedPreferences settings = getSharedPreferences(FILTER_PREFS_NAME, 0);

        // restore setter values
        showCultureCenters = settings.getBoolean(PREFS_CULTURE_CENTER, true);
        showLibraryOverlay = settings.getBoolean(PREFS_LIBRARY, true);
        showRecycleSmall = settings.getBoolean(PREFS_RECYCLE_SMALL, true);
        showRecyleCenter = settings.getBoolean(PREFS_RECYCLE_CENTER, true);
        showToilet = settings.getBoolean(PREFS_TOILET, true);
        showPlayground = settings.getBoolean(PREFS_PLAYGROUND, true);
        showTaxiStop = settings.getBoolean(PREFS_TAXI_STOP, true);

        // restore checkbox values
        CheckBox cultureCenterCb = (CheckBox)findViewById(R.id.culturalCenter);
        CheckBox libraryCb = (CheckBox)findViewById(R.id.library);
        CheckBox recycleSmallCb = (CheckBox)findViewById(R.id.recycleSmall);
        CheckBox recycleCenterCb = (CheckBox)findViewById(R.id.recycleCenter);
        CheckBox toiletCb = (CheckBox)findViewById(R.id.toilet);
        CheckBox playgroundCb = (CheckBox)findViewById(R.id.playground);
        CheckBox taxiCb = (CheckBox)findViewById(R.id.taxiStop);

        cultureCenterCb.setChecked(showCultureCenters);
        libraryCb.setChecked(showLibraryOverlay);
        recycleSmallCb.setChecked(showRecycleSmall);
        recycleCenterCb.setChecked(showRecyleCenter);
        toiletCb.setChecked(showToilet);
        playgroundCb.setChecked(showPlayground);
        taxiCb.setChecked(showTaxiStop);

        // Set Slider State
        if (settings.getBoolean(PREFS_SLIDER_OPEN, false)) {
            mSlidingDrawer.open();
        }

    }

    /**
     * Stores Filter Preferences
     */
    private void storeFilterPrefs() {
        // We need an Editor object to make preference changes.
        // All objects are from android.context.Context
        SharedPreferences settings = getSharedPreferences(FILTER_PREFS_NAME, 0);
        SharedPreferences.Editor editor = settings.edit();

        editor.putBoolean(PREFS_CULTURE_CENTER, showCultureCenters);
        editor.putBoolean(PREFS_LIBRARY, showLibraryOverlay);
        editor.putBoolean(PREFS_RECYCLE_SMALL, showRecycleSmall);
        editor.putBoolean(PREFS_RECYCLE_CENTER, showRecyleCenter);
        editor.putBoolean(PREFS_TOILET, showToilet);
        editor.putBoolean(PREFS_PLAYGROUND, showPlayground);
        editor.putBoolean(PREFS_TAXI_STOP, showTaxiStop);

        // Toast.makeText(this, Boolean.toString(slidingDrawer.isOpened()),
        // Toast.LENGTH_LONG);
        editor.putBoolean(PREFS_SLIDER_OPEN, mSlidingDrawer.isOpened());

        // Commit the edits!
        editor.commit();
    }

    /**
     * Handles the filter checkboxes
     * 
     * @param view
     */
    public void filterClickHandler(View view) {
        CheckBox cb = (CheckBox)findViewById(view.getId());

        switch (view.getId()) {
            case R.id.library:
                showLibraryOverlay = cb.isChecked();
                break;
            case R.id.culturalCenter:
                showCultureCenters = cb.isChecked();
                break;
            case R.id.recycleSmall:
                showRecycleSmall = cb.isChecked();
            case R.id.recycleCenter:
                showRecyleCenter = cb.isChecked();
                break;
            case R.id.toilet:
                showToilet = cb.isChecked();
                break;
            case R.id.playground:
                showPlayground = cb.isChecked();
                break;
            case R.id.taxiStop:
                showTaxiStop = cb.isChecked();
                break;

            default:
                break;
        }

        refreshView();
    }

    // checks if it's the first start of the application
    private void checkOnFirstStart() {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
        if (prefs.getBoolean("isFirstStart", true)) {
            Editor editor = prefs.edit();
            editor.putBoolean("isFirstStart", !onFirstStart());
            editor.commit();            
        }
    }
    
    //returns true when the method execution was successfull
    private boolean onFirstStart(){
        //Do things on first start
        return true;
    }

    @Override
    public void notifyChange() {
        mHandler.sendEmptyMessage(REFRESH);
    }

    @Override
    public void noDataConnection() {
        mHandler.sendEmptyMessage(NO_CONNECTION);
    }
}
